
#include <cstdio>
#include <BFile>
#include <BSocket>
#include <BStyleDocument>
#include <BApplication>
#include "member_BWidget.h"
#include "member_BStyle.h"
#include "IGlobal.h"

#ifdef linux
#include <errno.h>
#include <dlfcn.h>
#include <pthread.h>
#endif

using namespace BWE;

BApplication::BApplication(int argc, char** argv)
{
	if (app_handle != 0)
		return;
	App_InitGlobalMutex();

	app_done = false;
	app_style = new BStyle(BColor(255, 255, 255));

	app_extAlias.insert("tif", "tiff");
	app_extAlias.insert("jpeg", "jpg");
	app_extAlias.insert("wav", "wave");

#ifdef linux
	app_handle = pthread_self();
#ifdef BWE_DEBUG
	const char* libName = "libBWEd.so";
#else
	const char* libName = "libBWE.so";
#endif
	void* handle = dlopen(libName, RTLD_NOW);
	char pathname[256];
	int ret = dlinfo(handle, RTLD_DI_ORIGIN, pathname);
	if (ret == 0)
	{
		app_libPath = pathname;
	}

	if(!app_display)
		app_display = XOpenDisplay(0);

	//int fontSize = 0;
	//char** fontNames = XListFonts(app_display, "*", 1000, &fontSize);
	//for(int i = 0; i < fontSize; i++)
	//{
	//	puts(fontNames[i]);
	//}
	BString current = CurrentPath();
	this->setFont("times", 23);
#endif

#ifdef _WIN32
	app_handle = GetCurrentThread();
#ifdef BWE_DEBUG
	const char* libName = "BWEd.dll";
#else
	const char* libName = "BWE.dll";
#endif
	HMODULE module = GetModuleHandle(libName);
	char path[256];
	DWORD len = GetModuleFileNameA(module, path, 256);
	if (len > 0)
	{
		app_libPath = path;
		app_libPath.replace('\\', '/');
		app_libPath -= '/';
	}

	NONCLIENTMETRICS info;
	info.cbSize = sizeof(NONCLIENTMETRICS);
	if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &info, 0))
	{
		BString family = info.lfMessageFont.lfFaceName;
		this->setFont("msyh.ttc", 16);
	}
	LOGFONT logfont;
	if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, 0, &logfont, 0))
	{

	}
#endif

	if(app_libPath.empty())
	{
		puts("Locate librrary path failed.");
	}
	else
	{
		app_libPath -= libName;
	}
}
BApplication::~BApplication()
{

}

BString BApplication::CurrentPath()
{
	BString path;
	GetCurrentPath(path);
	return path;
}
bool BApplication::GetCurrentPath(BString& path)
{
	char buffer[256];
	buffer[0] = 0;
#ifdef linux
	if (NULL == getcwd(buffer, 256))
	{
		fprintf(stderr, "getcwd error: %s", strerror(errno));
	}
#endif

#ifdef _WIN32
	DWORD len = GetCurrentDirectoryA(256, buffer);
	for (DWORD i = 0; i < len; i++)
	{
		if (buffer[i] == '\\')
			buffer[i] = '/';
	}
#endif
	path = buffer;
	return true;
}
bool BApplication::SetCurrentPath(const BString& path)
{
	if (path.empty())
		return false;

#ifdef linux
	int ret = chdir(path.cstr());
	return ret > -1;
#endif

#ifdef _WIN32
	BOOL ret = ::SetCurrentDirectoryA(path.cstr());
	return ret == TRUE;
#endif
}

void BApplication::setStyleSheet(const BString& sheet)
{
	if (sheet.empty())
	{
		return;
	}
	BStyleDocument doc;
	if (BFile::Exist(sheet))
	{
		doc.load(sheet, app_style);
		printf("Load style sheet %s", sheet.cstr());
	}
	else
	{
		doc.read(sheet, app_style);
		printf("Read style sheet");
	}
	if (doc.message().size())
		printf(" message :\n%s\n", doc.message().cstr());
	else
		printf(" success.\n");
	for (int i = 0; i < app_windows.size(); i++)
	{
		IWindow* window = app_windows[i];
		if (BWidget* widget = window->boss)
		{
			widget_member(widget)->dirtyStyle = true;
			widget_member(widget)->refresh = true;
		}
	}
}
void BApplication::addStyleSheet(const BString& sheet)
{
	if (sheet.empty())
	{
		return;
	}
	BStyleDocument doc;
	if (BFile::Exist(sheet))
	{
		doc.load(sheet, app_style);
		printf("Load style sheet %s", sheet.cstr());
	}
	else
	{
		doc.read(sheet, app_style);
		printf("Read style sheet");
	}
	if (doc.message().size())
		printf(" message :\n%s\n", doc.message().cstr());
	else
		printf(" success.\n");
	for (int i = 0; i < app_windows.size(); i++)
	{
		IWindow* window = app_windows[i];
		if (BWidget* widget = window->boss)
		{
			widget_member(widget)->dirtyStyle = true;
			widget_member(widget)->refresh = true;
		}
	}
}

void BApplication::setStyle(BStyle* style)
{
	if (app_style != style)
	{
		app_style = style;
	}
	for (int i = 0; i < app_windows.size(); i++)
	{
		IWindow* window = app_windows[i];
		if (BWidget* widget = window->boss)
		{
			widget_member(widget)->dirtyStyle = true;
			widget_member(widget)->refresh = true;
		}
	}
}
BStyle* BApplication::style()
{
	return app_style;
}

void BApplication::setFont(const BString& family, int size)
{
	BFont* font = new BFont(family, size);
	setFont(font);
}
void BApplication::setFont(BFont* font)
{
	app_style->setFont(font);
	setStyle(app_style);
}
const BFont* BApplication::font()
{
	return app_style->font();
}

void BApplication::setFrequency(int frequency)
{
	if (app_frequency <= 0)
		app_frequency = 30;
	else
		app_frequency = frequency;
}
int BApplication::frequency()
{
	return app_frequency;
}
int BApplication::realFrequency()
{
	return app_realFrequency;
}

void BApplication::setClickInterval(double clickInterval)
{
	double interval = bLimit(clickInterval, 0.1, 5.0);
	if (app_clickInterval != interval)
	{
		app_clickInterval = interval;
	}
}
double BApplication::clickInterval()
{
	return app_clickInterval;
}

void BApplication::done(int code)
{
	app_code = code;
	app_done = true;
}
int BApplication::code()
{
	return app_code;
}

int BApplication::execute()
{
	while (!app_done)
	{
		App_CycleBegin();
		App_Event();
		App_Update();
		App_Frame();
		App_CycleEnd();
	}
	app_windows.clear();
	app_sockets.clear();
	return app_code;
}

void BApplication::addPluginPath(const BString& pluginPath)
{
	if (!app_pluginPaths.contain(pluginPath))
	{
		app_pluginPaths.append(pluginPath);
	}
}
void BApplication::addFontPath(const BString& fontPath)
{
	if (!app_fontPaths.contain(fontPath))
	{
		app_fontPaths.append(fontPath);
	}
}
void BApplication::addDataPath(const BString& dataPath)
{
	if (!app_dataPaths.contain(dataPath))
	{
		app_dataPaths.append(dataPath);
	}
}

void BApplication::removePluginPath(const BString& pluginPath)
{
	app_pluginPaths.remove(pluginPath);
}
void BApplication::removeFontPath(const BString& fontPath)
{
	app_fontPaths.remove(fontPath);
}
void BApplication::removeDataPath(const BString& dataPath)
{
	app_dataPaths.remove(dataPath);
}

int BApplication::pluginPathCount()
{
	return app_pluginPaths.size();
}
int BApplication::fontPathCount()
{
	return app_fontPaths.size();
}
int BApplication::dataPathCount()
{
	return app_dataPaths.size();
}

const BString& BApplication::pluginPath(int index)
{
	return app_pluginPaths(index);
}
const BString& BApplication::fontPath(int index)
{
	return app_fontPaths(index);
}
const BString& BApplication::dataPath(int index)
{
	return app_dataPaths(index);
}
